import { _decorator, BoxCollider, Collider, Component, CylinderCollider, game, isValid, Node, PhysicsGroup, quat, Quat, RigidBody, SphereCollider, tween, Vec3, VERSION } from 'cc';
import { EliminateToy } from './EliminateToy';
import EliminateConsts, { eliminateConsts } from './EliminateConst';
import { EliminateSlot } from './EliminateSlot';
import { eliminateGameManager } from './EliminateGameManager';
import { assetManager } from 'cc';
import { JsonAsset } from 'cc';
import { Tween } from 'cc';
const { ccclass, property } = _decorator;

export interface TriggerEventObj {
    type: TriggerEventObj,
    selfCollider: Collider,
    otherCollider: Collider,
    impl: any,
}

export enum PhyGroup {
    DEFAULT = 1 << 0,
    TOYS = 1 << 1,
    PLANE = 1 << 2,
    CHECK = 1 << 3,
    BOARD = 1 << 4,
    IN = 1 << 5,
    SLOT = 1 << 6,
    FLY = 1 << 7
}

@ccclass('EliminateSlotTrigger')
export class EliminateSlotTrigger extends Component {

    /** 下方的碰撞体，只有在消除槽里面有不同物体的时候启用 */
    @property(Collider)
    bottomCollider: Collider = null;

    @property(JsonAsset)
    toyRotationJson: JsonAsset = null;

    private boxCollider: Collider = null;
    private _boxs: Node[] = [];

    private stayY: number = 5;

    public enterSomething: boolean = false;
    /** 待消除队列 */
    public waitEnterNodes: Node[] = [];
    /** 待消除的队列 */
    public waitClearQueue: Node[][] = [];

    private leftPos: Vec3 = new Vec3(-1.5, 6, 16);
    private rightPos: Vec3 = new Vec3(1.5, 6, 16);

    /** 落入槽子的物体 */
    public get boxs() {
        return this._boxs;
    }

    public set boxs(v: Node[]) {
        this._boxs = v;
    }

    protected onLoad(): void {
        this.bottomCollider.enabled = false;
        this.boxCollider = this.node.getComponent(Collider);
    }

    start() {
        // this.node.uuid
    }

    protected onEnable(): void {
        this.boxCollider.on("onTriggerEnter", this.triggerEnter, this);
        this.boxCollider.on("onTriggerStay", this.triggerStay, this);
        this.boxCollider.on("onTriggerExit", this.triggerExit, this);
    }

    protected onDisable(): void {
        this.boxCollider.off("onTriggerEnter", this.triggerEnter, this);
        this.boxCollider.off("onTriggerStay", this.triggerStay, this);
        this.boxCollider.off("onTriggerExit", this.triggerExit, this);
    }

    private _dealEnterEvent(event: TriggerEventObj) {
        if (event.otherCollider.node['clear']) {
            console.log(`${event.otherCollider.node.name} 已经被标记为clear`);
            return;
        }

        let toyComp = event.otherCollider.node.getComponent(EliminateToy);
        if(!toyComp.node['canClear']) return;
        const rb = toyComp.node.getComponent(RigidBody);
        Tween.stopAllByTarget(toyComp.node);
        if (eliminateGameManager.game.isEliminating || this.boxs.length == eliminateConsts.eliminateLimit) {
            // 消除中
            if (this.boxs.indexOf(toyComp.node) >= 0) {
                console.log("boxs 里面有该物体了");
                return;
            }

            if (this.waitEnterNodes.indexOf(toyComp.node) < 0) {
                if (this.waitEnterNodes.length > 0) {
                    if (this.waitEnterNodes[0].getComponent(EliminateToy).toyId == toyComp.toyId) {
                        this.waitEnterNodes.push(toyComp.node);
                        if (this.waitEnterNodes.length >= eliminateConsts.eliminateLimit) {
                            // 进入待消除队列
                            this.waitClearQueue.push([this.waitEnterNodes[0], this.waitEnterNodes[1]]);
                        }
                    } else {
                        // 弹出去
                        rb && (rb.useGravity = true);
                        rb && (rb.group = PhyGroup.TOYS);
                        rb && rb.applyImpulse(new Vec3(0, 0, -10));
                        console.log("进入的东西跟等待消除队列的东西不同弹出去");
                        return;
                    }
                } else {
                    // 加入待消除队列
                    this.waitEnterNodes.push(toyComp.node);
                }
                this.waitEnterNodes.forEach((item: Node, index: number) => {
                    this._setRigidBodyToPos(item, index);
                });

                this.moveToysToTargetPos(this.waitEnterNodes);

                if (this.waitEnterNodes.length >= eliminateConsts.eliminateLimit) {
                    /** 清空缓冲数组 */
                    this.waitEnterNodes.length = 0;
                }
                // 进入待消除队列
                // this.waitClearQueue.push(this.waitEnterNodes);
                return;
            }

        } else {
            // 缓冲队列里面没有节点
            if (this.boxs.length > 0) {
                if (this.boxs[0]['clear']) return;
                const toyInBasketComp = this.boxs[0].getComponent(EliminateToy);

                if (toyComp && toyInBasketComp && toyComp != toyInBasketComp) {
                    if (toyComp.toyId == toyInBasketComp.toyId) {
                        // this.boxCollider.isTrigger = true;
                        if (this.boxs.indexOf(toyComp.node) < 0 && this.boxs.length < eliminateConsts.eliminateLimit) {
                            toyComp.enterSlot = true;
                            this.boxs.push(toyComp.node);
                        }
                    } else {
                        // 弹出去
                        const rb = toyComp.node.getComponent(RigidBody);
                        rb.useGravity = true;
                        rb.group = PhyGroup.TOYS;
                        rb.applyImpulse(new Vec3(0, 0, -15));
                        console.log("进入的东西跟槽子里面的东西不同弹出去");
                    }
                }
            } else {
                toyComp.enterSlot = true;
                // 直接推入数组
                this.boxs.push(toyComp.node);
            }

            this.boxs.forEach((item: Node, index: number) => {
                this._setRigidBodyToPos(item, index);
            });

            this.moveToysToTargetPos(this.boxs).then(() => {
                this.checkIsCanEliminate();
            });
        }
    }

    clearWaitNodesInBoxs(tag: string) {
        for (let i = this.waitEnterNodes.length - 1; i >= 0; i--) {
            let item = this.waitEnterNodes[i];
            if (item['clear'] && item['tag'] == tag) {
                console.log("清除clear 标记的节点");
                this.waitEnterNodes.splice(i, 1);
            }
        }
    }

    public moveToysToTargetPos(nodes: Node[]) {
        return new Promise((resolve, reject) => {
            nodes.forEach((item: Node, index: number) => {
                const rb = item.getComponent(RigidBody);
                rb.setLinearVelocity(new Vec3(0));
                rb.setAngularVelocity(new Vec3(0));
                rb.useGravity = false;
                if (rb.group != PhyGroup.IN) {
                    rb.group = PhyGroup.IN;
                }
                const name = item['tag'];
                const rotateX = this.toyRotationJson.json[name].rotateX;
                const rotateY = this.toyRotationJson.json[name].rotateY;
                const rotateZ = this.toyRotationJson.json[name].rotateZ;
                let quat = new Quat();
                Quat.fromEuler(quat, rotateX, rotateY, rotateZ);
                Tween.stopAllByTarget(item);
                if (index == 0) {
                    // item.setWorldPosition(this.leftPos);
                    // item.setRotation(quat);
                    // const targetRota = 
                    tween(item).to(0.3, { worldPosition: this.leftPos, rotation: quat }, { easing: 'quadInOut' }).call(resolve).start();
                    // item.setWorldPosition(new Vec3(-1, 5, 15));
                } else {
                    tween(item).to(0.3, { worldPosition: this.rightPos, rotation: quat }, { easing: 'quadInOut' }).start();
                    // item.setWorldPosition(this.rightPos);
                    // item.setRotation(quat);
                    // item.setWorldPosition(new Vec3(1, 5, 15));
                }
            });
        })

    }

    private _setRigidBodyToPos(nodeItem: Node, index: number) {
        if (nodeItem['clear']) return;
        if (eliminateGameManager.game.isEliminating) return;

        const rbItem = nodeItem.getComponent(RigidBody);
        if (rbItem.group != PhyGroup.IN) {
            rbItem.group = PhyGroup.IN;
        }
        rbItem.useGravity = false;
        const name = nodeItem['tag'];
        const rotateX = this.toyRotationJson.json[name].rotateX;
        const rotateY = this.toyRotationJson.json[name].rotateY;
        const rotateZ = this.toyRotationJson.json[name].rotateZ;
        let quat = new Quat();
        Quat.fromEuler(quat, rotateX, rotateY, rotateZ);

        nodeItem.setRotation(quat);
        if (index == 0) {
            nodeItem.setWorldPosition(this.leftPos);
        } else {
            nodeItem.setWorldPosition(this.rightPos);
        }
    }

    public triggerEnter(event: TriggerEventObj) {
        console.log("enter", event.otherCollider.node.name);
        this._dealEnterEvent(event);
        this.enterSomething = true;
    }

    public triggerStay(event: TriggerEventObj) {
        // this.boxs.forEach((item: Node, index: number) => {
        //     this._setRigidBodyToPos(item, index);
        // });
    }

    public triggerExit(event: TriggerEventObj) {
        const self = event.selfCollider;
        const other = event.otherCollider;
        if (other.node['clear']) return;

        this.enterSomething = false;
        if (other.node['myType'] == "toy") {
            const rb = other.getComponent(RigidBody);
            const cb = other.getComponent(Collider);
            rb.enabled = true;
            cb.enabled = true;

            if (rb) {
                rb.group = (PhyGroup.TOYS);
                (rb.useGravity = true);
                console.log("处罚exit 弹出去", other.node.name);
                rb.applyImpulse(new Vec3(0, 0, -10));
            }

            const toyComp = other.node.getComponent(EliminateToy);
            if (toyComp && this.boxs.indexOf(toyComp.node) >= 0) {
                console.log("删除：", toyComp.node.name);
                toyComp.enterSlot = false;
                // 可以触摸
                toyComp.canTouch = true;
                const inx = this.boxs.indexOf(toyComp.node);
                this.boxs.splice(inx, 1);
            }
        }
    }

    /**
     * 检查是否可以消除
     * @return {*}  {boolean}
     * @memberof EliminateSlotTrigger
     */
    checkIsCanEliminate(): boolean {
        if (this.boxs.length == eliminateConsts.eliminateLimit) {
            this.boxs.forEach(item => {
                const toyComp = item.getComponent(EliminateToy);
                // 锁定触摸
                toyComp.canTouch = false;
            });
            eliminateGameManager.uiManager.openDoor(true).then(() => {
                eliminateGameManager.game.eliminate(this.boxs).then(() => {
                    this.resetBoxs();
                    eliminateGameManager.uiManager.openDoor(false).then(() => {
                        console.log("门已经关闭");
                        eliminateGameManager.game.isEliminating = false;
                        // 查看待消除队列
                        this.moveWaitNodesToBoxs();
                        eliminateGameManager.game.checkHasPair();
                    });
                })
            });
            return true;
        } else {
            this.staticToys();
        }
        return false;
    }

    /**
     * 每消除一次从待消除列表里面取出一对
     * 将待消除队列里面的节点移动到boxs中并且检查是否可以消除
     */
    public moveWaitNodesToBoxs() {
        console.log("待消除队列的长度：", this.waitClearQueue.length);
        if (this.waitClearQueue.length > 0) {
            const pearNodes = this.waitClearQueue.shift();
            console.log("pearNodes is ", pearNodes);
            pearNodes.forEach((item, index) => {
                if (this.boxs.indexOf(item) < 0) {
                    this.boxs.push(item);
                }
            });
        } else {
            // 将waitEnterNodes 里面的节点移动到boxs里面
            this.waitEnterNodes.forEach(item => {
                if (this.boxs.indexOf(item) < 0) {
                    this.boxs.push(item);
                }
            });
        }
        this.checkIsCanEliminate();
    }

    removeFromBoxsOrWaitEnterNodes(node: Node) {
        if (this.boxs.indexOf(node) >= 0) {
            this.boxs.splice(this.boxs.indexOf(node), 1);
        }
        if (this.waitEnterNodes.indexOf(node) >= 0) {
            this.waitEnterNodes.splice(this.waitEnterNodes.indexOf(node), 1);
        }
    }



    /**
     * 使所用的刚体静止
     */
    public staticToys() {
        this.boxs.forEach(item => {
            if (!isValid(item, true)) return;
            const rb = item.getComponent(RigidBody);
            rb.useGravity = false;
            rb.setLinearVelocity(new Vec3(0));
            rb.setAngularVelocity(new Vec3(0));
        });
    }

    public resetBoxs() {
        this.boxs.length = 0;
        this.enterSomething = false;
    }

    update(deltaTime: number) {

    }
}

